﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TripleGame.Core;

namespace TripleGame.BatBoikoEngine
{
    public class TripleGameBatBoikoEngine:ITripleGameEngine
    {
        enum Direction { R, D, DR };

        private static int currentTurn = 0;

        public string EngineName
        {
            get { return "BatBoiko"; }
        }

        public void PerformMove(char[,] board, char playerLetter,
            out int startX, out int startY, out int endX, out int endY)
        {
            currentTurn++;
            #region Get Corners
            bool isCornerFree = true;
            for (int i = 0; i < 3; i++)
            {
                for (int j = board.GetLength(1) - 3 + i; j < board.GetLength(1); j++)
                {
                    if (board[i, j] != ' ')
                    {
                        isCornerFree = false;
                    }
                }
            }
            if (isCornerFree == true)
            {
                startY = 0;
                endY = 2;
                startX = board.GetLength(1) - 3;
                endX = board.GetLength(1) - 1;
                return;
            }

            isCornerFree = true;
            for (int i = board.GetLength(0) - 3; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < 4 - (board.GetLength(0) - i); j++)
                {
                    if (board[i, j] != ' ')
                    {
                        isCornerFree = false;
                    }
                }
            }
            if (isCornerFree == true)
            {
                startY = board.GetLength(0) - 3;
                endY = board.GetLength(0) - 1;
                startX = 0;
                endX = 2;
                return;
            }
            #endregion
            
            #region 3Moves
            bool is3MoveAvailable = false;
            int minCount = 10000;
            int bestStartX = -1, bestStartY = -1;
            Direction bestMove = Direction.D;
            char enemyLetter = (playerLetter == 'A' ? 'B':'A');
            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    int current;
                    if (Is3MovePossible(board, playerLetter, i, j, i + 2, j))
                    {
                        is3MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i + 1, j] = playerLetter;
                        board[i + 2, j] = playerLetter;
                        current = CountPossible3Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.D;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i + 1, j] = ' ';
                        board[i + 2, j] = ' ';
                    }
                    if (Is3MovePossible(board, playerLetter, i, j, i, j + 2))
                    {
                        is3MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i, j + 1] = playerLetter;
                        board[i, j + 2] = playerLetter;
                        current = CountPossible3Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.R;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i, j + 1] = ' ';
                        board[i, j + 2] = ' ';
                    }
                    if (Is3MovePossible(board, playerLetter, i, j, i + 2, j + 2))
                    {
                        is3MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i + 1, j + 1] = playerLetter;
                        board[i + 2, j + 2] = playerLetter;
                        current = CountPossible3Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.DR;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i + 1, j + 1] = ' ';
                        board[i + 2, j + 2] = ' ';
                    }
                }    
            }
            if (is3MoveAvailable)
            {
                startX = bestStartX;
                startY = bestStartY;
                if (bestMove == Direction.D)
                {
                    endX = startX;
                    endY = startY + 2;
                }
                else if (bestMove == Direction.R)
                {
                    endX = startX + 2;
                    endY = startY;
                }
                else
                {
                    endX = startX + 2;
                    endY = startY + 2;
                }
                return;
            }
            #endregion

            #region 2Moves
            bool is2MoveAvailable = false;
            minCount = 10000;
            bestStartX = -1;
            bestStartY = -1;
            bestMove = Direction.D;
            enemyLetter = (playerLetter == 'A' ? 'B' : 'A');
            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    int current;
                    if (Is2MovePossible(board, playerLetter, i, j, i + 2, j))
                    {
                        is2MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i + 1, j] = playerLetter;
                        board[i + 2, j] = playerLetter;
                        current = CountPossible2Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.D;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i + 1, j] = ' ';
                        board[i + 2, j] = ' ';
                    }
                    if (Is2MovePossible(board, playerLetter, i, j, i, j + 2))
                    {
                        is2MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i, j + 1] = playerLetter;
                        board[i, j + 2] = playerLetter;
                        current = CountPossible2Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.R;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i, j + 1] = ' ';
                        board[i, j + 2] = ' ';
                    }
                    if (Is2MovePossible(board, playerLetter, i, j, i + 2, j + 2))
                    {
                        is2MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i + 1, j + 1] = playerLetter;
                        board[i + 2, j + 2] = playerLetter;
                        current = CountPossible2Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.DR;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i + 1, j + 1] = ' ';
                        board[i + 2, j + 2] = ' ';
                    }
                }
            }
            if (is2MoveAvailable)
            {
                startX = bestStartX;
                startY = bestStartY;
                if (bestMove == Direction.D)
                {
                    endX = startX;
                    endY = startY + 2;
                }
                else if (bestMove == Direction.R)
                {
                    endX = startX + 2;
                    endY = startY;
                }
                else
                {
                    endX = startX + 2;
                    endY = startY + 2;
                }
                return;
            }
            #endregion

            #region 1Moves
            bool is1MoveAvailable = false;
            minCount = 10000;
            bestStartX = -1;
            bestStartY = -1;
            bestMove = Direction.D;
            enemyLetter = (playerLetter == 'A' ? 'B' : 'A');
            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    int current;
                    if (Is1MovePossible(board, playerLetter, i, j, i + 2, j))
                    {
                        is1MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i + 1, j] = playerLetter;
                        board[i + 2, j] = playerLetter;
                        current = CountPossible1Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.D;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i + 1, j] = ' ';
                        board[i + 2, j] = ' ';
                    }
                    if (Is1MovePossible(board, playerLetter, i, j, i, j + 2))
                    {
                        is1MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i, j + 1] = playerLetter;
                        board[i, j + 2] = playerLetter;
                        current = CountPossible1Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.R;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i, j + 1] = ' ';
                        board[i, j + 2] = ' ';
                    }
                    if (Is1MovePossible(board, playerLetter, i, j, i + 2, j + 2))
                    {
                        is1MoveAvailable = true;
                        board[i, j] = playerLetter;
                        board[i + 1, j + 1] = playerLetter;
                        board[i + 2, j + 2] = playerLetter;
                        current = CountPossible1Moves(board, enemyLetter);
                        if (current < minCount)
                        {
                            minCount = current;
                            bestMove = Direction.DR;
                            bestStartX = j;
                            bestStartY = i;
                        }
                        board[i, j] = ' ';
                        board[i + 1, j + 1] = ' ';
                        board[i + 2, j + 2] = ' ';
                    }
                }
            }
            if (is1MoveAvailable)
            {
                startX = bestStartX;
                startY = bestStartY;
                if (bestMove == Direction.D)
                {
                    endX = startX;
                    endY = startY + 2;
                }
                else if (bestMove == Direction.R)
                {
                    endX = startX + 2;
                    endY = startY;
                }
                else
                {
                    endX = startX + 2;
                    endY = startY + 2;
                }
                return;
            }
            #endregion

            if (board[2, 0] == playerLetter && board[3, 1] == playerLetter && board[4, 2] == playerLetter)
            {
                startX = 0;
                startY = 2;
                endX = 2;
                endY = 4;
            }
            else
            {
                startX = 7;
                startY = 0;
                endX = 9;
                endY = 2;
            }
        }

        private int CountPossible3Moves(char[,] board, char playerLetter)
        {
            int possibleMoves = 0;
            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    if (Is3MovePossible(board, playerLetter, i, j, i + 2, j))
                    {
                        possibleMoves++;
                    }
                    if (Is3MovePossible(board, playerLetter, i, j, i, j + 2))
                    {
                        possibleMoves++;
                    }
                    if (Is3MovePossible(board, playerLetter, i, j, i + 2, j + 2))
                    {
                        possibleMoves++;
                    }
                }
            }
            return possibleMoves;
        }

        private int CountPossible2Moves(char[,] board, char playerLetter)
        {
            int possibleMoves = 0;
            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    if (Is2MovePossible(board, playerLetter, i, j, i + 2, j))
                    {
                        possibleMoves++;
                    }
                    if (Is2MovePossible(board, playerLetter, i, j, i, j + 2))
                    {
                        possibleMoves++;
                    }
                    if (Is2MovePossible(board, playerLetter, i, j, i + 2, j + 2))
                    {
                        possibleMoves++;
                    }
                }
            }
            return possibleMoves;
        }

        private int CountPossible1Moves(char[,] board, char playerLetter)
        {
            int possibleMoves = 0;
            for (int i = 0; i < board.GetLength(0); i++)
            {
                for (int j = 0; j < board.GetLength(1); j++)
                {
                    if (Is1MovePossible(board, playerLetter, i, j, i + 2, j))
                    {
                        possibleMoves++;
                    }
                    if (Is1MovePossible(board, playerLetter, i, j, i, j + 2))
                    {
                        possibleMoves++;
                    }
                    if (Is1MovePossible(board, playerLetter, i, j, i + 2, j + 2))
                    {
                        possibleMoves++;
                    }
                }
            }
            return possibleMoves;
        }

        private bool Is3MovePossible(char[,] board, char playerLetter, int startI, int startJ, int endI, int endJ)
        {
            if (endI >= board.GetLength(0) || endJ >= board.GetLength(1))
            {
                return false;
            }
            return ((board[startI, startJ] == ' ' && board[endI, endJ] == ' ' &&
                board[(startI + endI) / 2, (startJ + endJ) / 2] == ' '));
        }

        private bool Is2MovePossible(char[,] board, char playerLetter, int startI, int startJ, int endI, int endJ)
        {
            if (endI >= board.GetLength(0) || endJ >= board.GetLength(1))
            {
                return false;
            }
            return ((board[startI, startJ] == playerLetter && board[endI, endJ] == ' ' &&
                board[(startI + endI) / 2, (startJ + endJ) / 2] == ' ') ||
                (board[startI, startJ] == ' ' && board[endI, endJ] == playerLetter &&
                board[(startI + endI) / 2, (startJ + endJ) / 2] == ' ') ||
                (board[startI, startJ] == ' ' && board[endI, endJ] == ' ' &&
                board[(startI + endI) / 2, (startJ + endJ) / 2] == playerLetter));
        }

        private bool Is1MovePossible(char[,] board, char playerLetter, int startI, int startJ, int endI, int endJ)
        {
            if (endI >= board.GetLength(0) || endJ >= board.GetLength(1))
            {
                return false;
            }
            return ((board[startI, startJ] == playerLetter && board[endI, endJ] == ' ' &&
                board[(startI + endI) / 2, (startJ + endJ) / 2] == playerLetter) ||
                (board[startI, startJ] == playerLetter && board[endI, endJ] == playerLetter &&
                board[(startI + endI) / 2, (startJ + endJ) / 2] == ' ') ||
                (board[startI, startJ] == ' ' && board[endI, endJ] == playerLetter &&
                board[(startI + endI) / 2, (startJ + endJ) / 2] == playerLetter));
        }
    }
}
